// store state getters modules actions mutations
class Store {
  constructor(options) {
    const { state, getters, mutations, actions, modules, plugins = [] } = options
    this._state = state || {}
    this._getters = getters || {}
    this._mutations = mutations || {}
    this._actions = actions || {}
    this._modules = modules || {}
    this.registerModules(this._modules, this._state)
    this.subscribers = []
    plugins.forEach(plugin => {
      plugin(this)
    })
  }

  get state() {
    return this._state
  }

  get getters() {
    const res = {}
    Object.keys(this._getters).map(key => {
      res[key] = (this._getters[key])(this._state)
    })
    return res
  }

  commit = (mutationType, payload) => {
    const getData = (mutationType, state) => {
      const index = mutationType.indexOf('/')
      if (index > -1) {
        return getData(mutationType.slice(index + 1), state[mutationType.slice(0, index)])
      }
      return {
        state,
        mutationType
      }
    }

    const {
      mutationType: finalMutationType, state
    } = getData(mutationType, this._state)
    const mutation = this._mutations[finalMutationType]
    mutation(state, payload)
    this.subscribers.forEach(sub => {
      sub({ type: mutationType, payload }, this.state);
    });
  }



  dispatch = (actionType, payload) => {
    const action = this._actions[actionType]
    action({commit: this.commit, state: this._state}, payload)
  }

  get = (getterType) => {
    const getter = this._getters[getterType]
    return getter(this._state)
  }

  registerModules = (modules, rootState) => {
    Object.keys(modules).forEach(moduleName => {
      const module = this._modules[moduleName]
      if (module.state) {
        rootState[moduleName] = module.state
      }
      if (module.mutations) {
        this._mutations = { ...this._mutations, ...module.mutations}
      }
      if (module.actions) {
        this._actions = { ...this._actions, ...module.actions}
      }
      if (module.getters) {
        this._getters = { ...this._getters, ...module.getters}
      }
      if (module.modules) {
        registerModules(module.modules, rootState[moduleName])
      }
    })
  }

  subscribe = (fn) => {
    if (!this.subscribers.includes(fn)){
      this.subscribers.push(fn)
    }
    return () => {
      const index = this.subscribers.indexOf(fn)
      if (index > -1) {
        this.subscribers.splice(index, 1)
      }
    }
  }
}
